home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / opengl / xlib / overlay.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  28.0 KB  |  726 lines

  1. /*
  2.  * Copyright 1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*
  18.  * overlay:  an openGL-Xlib "overlay" example program.  
  19.  *
  20.  *              overlay is the openGL "after" version of the IrisGL 
  21.  *              "before" program, ~4Dgifts/examples/grafix/overlay.c
  22.  *
  23.  *           - b key toggles the bell off or on.
  24.  *           - Esc key:  exit
  25.  *
  26.  *       overlay demonstrates defining an overlay window coincident with
  27.  *       the GL window, changing size as the GL window does, etc.  both
  28.  *       these windows are created as children of a parent X window.  two
  29.  *       window attribute lists are defined for each child window--in the
  30.  *       GL window's case, if the requested GLX_BUFFER_SIZE is less than
  31.  *       12 (this will be a doublebuffered colormap window where we want 
  32.  *       to use more than 16 colors if possible), then we request a visual 
  33.  *       from glXChooseVisual with only DOUBLEBUFFER specified to get back
  34.  *       the deepest visual the current system has.  similiarly for the
  35.  *       overlay window, if a request for GLX_LEVEL of 2 fails, then we
  36.  *       revert to asking for GLX_LEVEL of 1 and if this fails, exit the 
  37.  *       program.
  38.  *
  39.  *                                    ratmandu -- ported to openGL, aug, '93
  40.  */
  41.  
  42. #include <stdio.h>
  43. #include <GL/glx.h>
  44. #include <GL/gl.h>
  45. #include <GL/glu.h>
  46. #include <stdlib.h>
  47. #include <X11/keysym.h>
  48. #include <X11/Xlib.h>
  49. #include <X11/Xutil.h>
  50.  
  51. #define top     0                            /* parent X window array index */
  52. #define GLwin   1                   /* doublebuffer'd colormap GL win index */
  53. #define OLwin   2                   /* overlay (LEVEL 2 or 1) GL win index  */
  54. #define WINMAX  3                               /* number of unique windows */
  55.  
  56. static void openwindow(char *);
  57. static void initGL(void);
  58. static void clean_exit(void);
  59. static void drawball(void);
  60. static void drawovers(void);
  61. static int rampup(short, short, short, short, short, short, short, short);
  62. void Winset(int);
  63.  
  64. Display *dpy;                         /* X server connection                */
  65. Atom del_atom;                        /* for possibility of WM killing app  */
  66. int xsize, ysize;                     /* current size-of-window keepers     */
  67. Window glwins[WINMAX];                /* array for GL/OL window ids         */
  68. GLXContext glcontexts[WINMAX];        /* array for GL/OL window context ids */
  69. GLUquadricObj *quadObj;               /* used to make the two spheres with  */
  70. XEvent event;                         /* needs to be global for XIfEvent    */
  71. int bell;                             /* flag for turning off/on Xbell()    */
  72. int BIGcmap;                          /* for low-end machines w/less colors */
  73. unsigned short mycolortbl[83];        /* color array for when ball falls    */
  74. int black, red, green, yellow, blue,  /* cmap indices identifiers           */
  75.     magenta, cyan, white, beige;
  76. int OLred, OLgreen, OLcyan;           /* overlay color handles saved out by */
  77.                       /* returned vals from XAllocNamedColor*/
  78.  
  79.  
  80.  
  81. main (int argc, char **argv) 
  82. {
  83.     int myExpose, myKeyPress;                   /* store which events occur */
  84.     int firstPass;                     /* for initially turning on the bell */
  85.     KeySym keysym;
  86.     char buf[4];
  87.  
  88.  
  89.  
  90.     myExpose = myKeyPress = GL_FALSE;
  91.     firstPass = GL_TRUE;
  92.  
  93.     openwindow(argv[0]);                       /* define/setup window stuff */
  94.  
  95.     initGL();                                  /* initialize GL stuff       */
  96.  
  97.     if (BIGcmap)                               /* depending on the visual's */
  98.         rampup (12, 82, 255, 255, 0, 255, 0, 0); /* returned colormap_size, */
  99.     else                                         /* we'll either make a big */
  100.         rampup (5, 15, 255, 255, 0, 255, 0, 0);  /* or a small color ramp   */
  101.  
  102.     while (GL_TRUE) {                      /* main loop:  get/process input */
  103.  
  104.         glFlush();                            /* For proper DGL performance */
  105.  
  106.     /* this "do while" loop does the `get events' half of the "get events,
  107.      *  process events" action of the infinite while.  this is to ensure
  108.      *  the event queue is always drained before the events that have come
  109.      *  in are processed.
  110.      */
  111.         while (XEventsQueued(dpy,QueuedAfterReading)) { 
  112.                                    /* XEventsQueued(dpy,QueuedAfterReading)
  113.                                     * is like qtest()--it only tells you if
  114.                                     * there're any events presently in the
  115.                                     * queue.  it does not disturb the event
  116.                                     * queue's contents in any way.
  117.                                     */
  118.  
  119.             XNextEvent(dpy, &event);
  120.             switch (event.type) {
  121.  
  122.             /* "Expose" events are sort of like "REDRAW" in gl-speak in
  123.              *  terms of when a window becomes visible, or a previously
  124.              *  invisible part becomes visible.
  125.              */
  126.                 case Expose:                                   /* Exposures */
  127.                     myExpose = GL_TRUE;
  128.                     break;
  129.  
  130.             /* "ConfigNotify" events are like "REDRAW" in terms of changes
  131.              *   to a window's size or position.  Instead of making a 
  132.          *   separate "myConfigure" flag, we'll simply redefine the 
  133.          *   window's new size now and set the "myExpose" flag which 
  134.          *   will come back around and redraw everything.
  135.              */
  136.                 case ConfigureNotify:                 /* Resize GL manually */
  137.                     if (event.xconfigure.window == glwins[top]) {
  138.             /* save the changed width/height of the parent X window */
  139.                         xsize = event.xconfigure.width;
  140.                         ysize = event.xconfigure.height;
  141.             XMoveResizeWindow(dpy, glwins[OLwin], 0,0, xsize,ysize);
  142.             XMoveResizeWindow(dpy, glwins[GLwin], 0,0, xsize,ysize);
  143.             XFlush(dpy);
  144.             Winset(OLwin);
  145.             glViewport(0, 0, xsize-1, ysize-1);
  146.             glLoadIdentity();
  147.             gluOrtho2D(0.0, 1.0, 0.0, 1.0);
  148.             Winset(GLwin);
  149.             glViewport(0, 0, xsize-1, ysize-1);
  150.             glLoadIdentity();
  151.             gluOrtho2D(0.0, 1.0, 0.0, 1.0);
  152.             myExpose = GL_TRUE;
  153.                     }
  154.                     break;
  155.  
  156.  
  157.             /* "ClientMessage" is generated if the WM itself is being
  158.              *  gunned down and sends an exit signal to any running prog.
  159.              */
  160.                 case ClientMessage:
  161.                     if (event.xclient.data.l[0] == del_atom)
  162.                         clean_exit();
  163.                     break;
  164.  
  165.  
  166.             /* "KeyPress" events are those that would be generated before
  167.              *   whenever queueing up any KEYBD key via qdevice.
  168.              */
  169.                 case KeyPress:
  170.                    /* save out which unmodified key (i.e. the  key was
  171.                     *  not modified w/something like "Shift", "Ctrl",
  172.                     *  or "Alt") got pressed for use below.
  173.                     */
  174.                     XLookupString((XKeyEvent *)&event, buf, 4, &keysym, 0);
  175.                     myKeyPress = GL_TRUE;
  176.                     break;
  177.  
  178.             }  /* end switch (event.type) */
  179.  
  180.  
  181.         }  /* end while (XEventsQueued(dpy,QueuedAfterReading)) { */
  182.  
  183.         /* On an "Expose" event, [re]draw the just opened, popped, moved,
  184.          * resized or de-iconized  window
  185.          */
  186.         if (myExpose) {
  187.         if (firstPass) {
  188.             bell = GL_TRUE;
  189.         firstPass = GL_FALSE;
  190.             }
  191.             Winset(OLwin);                         /* redraw overlay window */
  192.             drawovers();
  193.             Winset(GLwin);                             /* redraw GL window  */
  194.             drawball();                                /* draw the GL stuff */
  195.             myExpose = GL_FALSE;             /* reset flag--queue now empty */
  196.         }
  197.  
  198.         /*
  199.          * On a keypress of
  200.          *  - b key toggles the bell in the GL window.
  201.          *  - Esc key:  exit.
  202.          */
  203.         if (myKeyPress) {
  204.  
  205.             if (keysym == XK_b) {
  206.                 bell = (bell == GL_TRUE) ? GL_FALSE : GL_TRUE;
  207.                 fprintf(stderr,"bell now = %d\n", bell);
  208.             } else if (keysym == XK_Escape) {
  209.                 clean_exit();
  210.             }
  211.             myKeyPress = GL_FALSE;           /* reset flag--queue now empty */
  212.         }
  213.  
  214.         drawball();
  215.     }
  216. }
  217.  
  218.  
  219. #define QTEST() XEventsQueued(dpy, QueuedAfterFlush)
  220.  
  221.  
  222. /* drawball:  the only drawback about this way of drawing the moving "ball" 
  223.  *            is any time *any* event occurs--manipulating the window, 
  224.  *            pressing a mouse button or keyboard key--logic flow will
  225.  *            entirely drop out of drawball, read the event, and then come
  226.  *            back into drawball not picking up where it left off, but 
  227.  *            starting all over again....  for anyone who likes puzzles, if 
  228.  *            you work up a a swank solution to this so the ball doesn't 
  229.  *            have to "restart" each time, i'd appreciate "hearing" from 
  230.  *            you at dave@sgi.com.
  231.  */
  232. static void drawball(void) {
  233.  
  234.     float heat, rate;
  235.     short val = 0;
  236.     int i, j, xpos, ypos;
  237.     float yspd = 0.0, yaccel = -1.0, yacc = -.4, yreflect = -0.6;
  238.  
  239.     for (i = j = 34; i<940 && j<940 && !(QTEST()); i = i+6, j = j+6) {   
  240.     glIndexi(blue);                /* roll the ball up and to the right */
  241.     glClear(GL_COLOR_BUFFER_BIT); 
  242.     if (bell && ((i==210) || (i==510) || (i==810)))
  243.         XBell(dpy, 80);                      /* ring bell if specified  */
  244.     if ((i>250) && (i<530))                  /* the ball gets to the    */
  245.         glIndexi(beige);                     /* next rectangle, as well */
  246.     else if ((i>530) && (i<810))             /* change the ball's color */
  247.         glIndexi(magenta);
  248.     else if (i>810)
  249.         glIndexi(white);
  250.     else
  251.         glIndexi(yellow);
  252.  
  253.         glPushMatrix(); 
  254.             glTranslatef((float)i/940.0, (float)j/940.0, 0.0); 
  255.             gluDisk(quadObj, 0.0, 0.035, 32, 1); 
  256.         glPopMatrix();
  257.  
  258.         glXSwapBuffers(dpy, glwins[GLwin]);
  259.     }
  260.  
  261.     yspd = 0.0;
  262.     if (BIGcmap) {
  263.     heat = 82.0; 
  264.         rate = 1.0;
  265.     } else { 
  266.     heat = 15.0;
  267.     rate = 0.144;
  268.     }
  269.     for (xpos=1, ypos=990; ypos>=25 && !(QTEST()); xpos++, ypos+=yspd) {
  270.         glIndexi(blue);                 /* drop the ball back to the bottom */
  271.         glClear(GL_COLOR_BUFFER_BIT);                 
  272.         heat = heat - rate;
  273.         glIndexi(mycolortbl[(int) heat]);        /* change the ball's color */
  274.         yspd += yacc;                            /* as it falls             */
  275.         
  276.         glPushMatrix(); 
  277.             glTranslatef(0.96, ypos/990.0, 0.0); 
  278.             gluDisk(quadObj, 0.0, 0.035, 32, 1); 
  279.         glPopMatrix();
  280.  
  281.         glXSwapBuffers(dpy, glwins[GLwin]);
  282.     }
  283.  
  284.     yspd = -60.0;
  285.     for (xpos=990, ypos=34; xpos >= 0 && !(QTEST()); xpos -= 5) {
  286.         if (ypos <= 34)              /* roll the ball back to the beginning */
  287.             yspd *= yreflect;                   /* and keep updating its'   */
  288.         glIndexi(blue);                         /* bounce-ability per frame */
  289.         glClear(GL_COLOR_BUFFER_BIT); 
  290.         glIndexi(yellow);
  291.         ypos += yspd;
  292.         yspd += yaccel;
  293.  
  294.         glPushMatrix();
  295.             glTranslatef(xpos/990.0, ypos/990.0, 0.);
  296.             gluDisk(quadObj, 0.0, 0.035, 32, 1);
  297.         glPopMatrix();
  298.  
  299.         glXSwapBuffers(dpy, glwins[GLwin]);
  300.     }
  301. }
  302.  
  303.  
  304.  
  305. /*  clean up before exiting
  306.  */
  307. static void clean_exit(void)
  308. {
  309.     Winset(OLwin);
  310.     glIndexi(0);
  311.     glClear(GL_COLOR_BUFFER_BIT);
  312.     Winset(GLwin);
  313.     XCloseDisplay(dpy);
  314.     exit(0);
  315. }
  316.  
  317.  
  318.  
  319. Colormap GLcmap, OLcmap;  /* need both these handles in openwindow & initGL */
  320.  
  321.   /* with the GL and overlay windows, we're defining two kinds of visuals:
  322.    * GLwinattribList and OLwinattribList are our "first choices", but if
  323.    * we're on minimum (8-bit) configuration systems, then we'll settle
  324.    * for whatever the deepest visual is available for the GL window 
  325.    * (GLwinattribList2) and for a LEVEL 1 visual for overlays 
  326.    * (OLwinattribList2) which, apparently, if nothing else, is ALWAYS 
  327.    * supposed to exist on ANY sgi machine.
  328.    */
  329. static int GLwinattribList[] = { GLX_DOUBLEBUFFER,         /* first choices */
  330.                  GLX_BUFFER_SIZE, 12, 
  331.                  None };
  332. static int OLwinattribList[] = { GLX_LEVEL, 2, None };
  333.  
  334. static int GLwinattribList2[] = { GLX_DOUBLEBUFFER,        /*  fallbacks    */
  335.                                   None };
  336. static int OLwinattribList2[] = { GLX_LEVEL, 1, None };
  337.  
  338.  
  339. /* WaitForNotify:
  340.  *   used to make sure the MapWindow() calls inside openwindow() occur
  341.  *   beFORE glXMakeCurrent() is invoked so as to avoid a race condition.
  342.  */
  343. static Bool WaitForNotify(Display *d, XEvent *e, char *arg) {
  344.     return (e->type == MapNotify) && (e->xmap.window == (Window)arg);
  345. }
  346.  
  347.  
  348. /* openwindow:
  349.  *   open a window.  in this case, make an X window that is the parent of
  350.  *   both the GL window and the overlay window.  There is a bug in X where,
  351.  *   even though one defines the events one is interested in reading via
  352.  *   the XSetWindowAttributes structure and then including that structure
  353.  *   as the last parameter to the XCreateWindow() call, the events 
  354.  *   nevertheless get dropped on the floor and are not picked up.  hence
  355.  *   the need to call XSelectInput() explicitly.  this shud NOT need to be
  356.  *   done, but at this point the hack inclusion of XSelectInput is necessary.
  357.  */
  358. static void openwindow(char *progname)
  359. {
  360.     XSizeHints Winhints;                         /* used to fix window size */
  361.     XVisualInfo *GLvi, *OLvi;       /* visual for the GL and overlay window */
  362.     XSetWindowAttributes GLswa, OLswa;        /* win attributes structures  */
  363.     int scrnnum;                              /* X screen number            */
  364.     int xorig, yorig;                         /* window (upper-left) origin */
  365.     int scrnheight;
  366.  
  367.  
  368.   /* Connect to the X server and get screen info */
  369.     if ((dpy = XOpenDisplay(NULL)) == NULL) {
  370.         fprintf(stderr, "%s: cannot connect to X server %s\n",
  371.                                  progname, XDisplayName(NULL));
  372.         exit(1);
  373.     }
  374.     scrnnum = DefaultScreen(dpy);
  375.     scrnheight = DisplayHeight(dpy, scrnnum);
  376.  
  377.     xorig = 0;  yorig = 0;                    /* define window initial size */
  378.     xsize = 200; ysize = 200;
  379.  
  380.   /* first create the top level X window which will be the parent to both
  381.    * the singlebuffer and doublebuffer rendering windows
  382.    */
  383.     glwins[top] = XCreateSimpleWindow(dpy, RootWindow(dpy, scrnnum),
  384.                                       xorig, yorig, xsize, ysize, 0, 0, 0);
  385.     if (!(glwins[top])) {
  386.         fprintf(stderr,"%s: couldn't create \"parent\" X window\n",progname);
  387.         exit(1);
  388.     }
  389.    /* including this call to XSelectInput shud not be necessary, but there's
  390.     * a bug, so we have to resort to this hackaround.
  391.     */
  392.     XSelectInput(dpy, glwins[top], StructureNotifyMask | 
  393.                            ExposureMask | KeyPressMask);
  394.  
  395.   /* define the string that will show up in the window title bar (and icon) */
  396.     XStoreName(dpy, glwins[top], "overlay demo program");
  397.  
  398.   /*  Now specify the values for the Window Aspect Hints we want to
  399.    *  enforce so that the aspect ratio of 1 to 1 will always be
  400.    *  maintained when the parent X window is resized.  Also specify
  401.    *  the minimum size (80x80) we will allow this window to shrink to.
  402.    */
  403.     Winhints.width  = xsize;          /* specify desired x/y size of window */
  404.     Winhints.height = ysize;
  405.     Winhints.min_width    = xsize;
  406.     Winhints.max_width    = scrnheight-1;
  407.     Winhints.min_height   = ysize;
  408.     Winhints.max_height   = scrnheight-1;
  409.     Winhints.min_aspect.x = 1;
  410.     Winhints.max_aspect.x = 1;
  411.     Winhints.min_aspect.y = 1;
  412.     Winhints.max_aspect.y = 1;
  413.                                              /* set the corresponding flags */
  414.     Winhints.flags        = USSize|PMaxSize|PMinSize|PAspect;
  415.     XSetWMNormalHints(dpy, glwins[top], &Winhints);
  416.  
  417.   /* now define and create the GL window and it's accompanying overlay win */
  418.  
  419.   /* first, get the appropriate visuals */
  420.     GLvi = glXChooseVisual(dpy, scrnnum, GLwinattribList);
  421.     if (GLvi == NULL) {   /* if NULL, our request failed--try a simpler one */
  422.         fprintf(stderr, "Unable to obtain a 12-bit deep doublebuffered ");
  423.         fprintf(stderr, "colorindex visual\n");
  424.         fprintf(stderr, "Now will try for max depth avail on this system...\n");
  425.         GLvi = glXChooseVisual(dpy, scrnnum, GLwinattribList2);
  426.     }
  427.         /* hackalong to test for 8-bit systems--if we're limited to 16
  428.      * colors then just define the actual colors we use in the 
  429.      * first five colormap indices.
  430.      */
  431.     if (BIGcmap = (GLvi->colormap_size > 16) ? GL_TRUE : GL_FALSE) {
  432.     black   = 0;
  433.     red     = 1; 
  434.     green   = 2; 
  435.     yellow  = 3;
  436.     blue    = 4;
  437.     magenta = 5;
  438.     cyan    = 6;
  439.     white   = 7;
  440.     beige   = 8;
  441.     } else {
  442.     beige   = 0;
  443.     white   = 1;
  444.     magenta = 2;
  445.     yellow  = 3;
  446.     blue    = 4;
  447.     }
  448.     OLvi = glXChooseVisual(dpy, DefaultScreen(dpy), OLwinattribList);
  449.     if (OLvi == NULL) {   /* if NULL, our request failed--try a simpler one */
  450.         fprintf(stderr, "Unable to obtain a LEVEL 2 overlay visual\n");
  451.         fprintf(stderr, "Now will try for LEVEL 1 overlay visual...\n");
  452.         OLvi = glXChooseVisual(dpy, scrnnum, OLwinattribList2);
  453.         if (OLvi == NULL) {
  454.             fprintf(stderr, "sorry, no \"overlay\" bitplanes on this system\n");
  455.             clean_exit();
  456.         }
  457.     }
  458.  
  459.   /* now create the appropriate GL contexts */
  460.     glcontexts[GLwin] = glXCreateContext(dpy, GLvi, 0, GL_TRUE);
  461.     glcontexts[OLwin] = glXCreateContext(dpy, OLvi, None, GL_TRUE);
  462.  
  463.        /* create the two colormaps */
  464.     GLcmap = XCreateColormap(dpy, RootWindow(dpy, GLvi->screen),
  465.                            GLvi->visual, AllocAll);
  466.     if (GLcmap == NULL) {
  467.     fprintf(stderr, "ERROR:  no writable \"GLwin colormap\"(???)\n");
  468.     clean_exit();
  469.     }
  470.     OLcmap = XCreateColormap(dpy, RootWindow(dpy, OLvi->screen),
  471.                            OLvi->visual, AllocNone);
  472.     if (OLcmap == NULL) {
  473.         fprintf(stderr, "ERROR:  no writable \"Overlay colormap\"\n");
  474.         clean_exit();
  475.     }
  476.  
  477.   /* now create both windows */
  478.     GLswa.border_pixel = 0;
  479.     GLswa.colormap   = GLcmap;
  480.              /* express interest in events */;
  481.     GLswa.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask; 
  482.     glwins[GLwin]    = XCreateWindow(dpy, glwins[top],
  483.                        xorig, yorig, xsize, ysize,
  484.                        0, GLvi->depth, InputOutput, GLvi->visual,
  485.                        CWBorderPixel|CWColormap|CWEventMask, &GLswa);
  486.     OLswa.border_pixel = 0;
  487.     OLswa.colormap    = OLcmap;
  488.     OLswa.win_gravity = UnmapGravity;
  489.     OLswa.bit_gravity = NorthWestGravity;
  490.     OLswa.background_pixel = BlackPixel(dpy, OLvi->screen);    
  491.              /* express interest in events */;
  492.     OLswa.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
  493.     glwins[OLwin]    = XCreateWindow(dpy, glwins[top],
  494.                        xorig, yorig, xsize, ysize,
  495.                        0, OLvi->depth, InputOutput, OLvi->visual,
  496.                        CWBorderPixel|CWColormap|CWEventMask, &OLswa);
  497.  
  498.   /* now map all three windows using XIfEvent to prevent race conditions
  499.    * for the children GL and overlay windows (which are the only ones we'll
  500.    * ever invoke in glXMakeCurrent())
  501.    */
  502.     XMapWindow(dpy, glwins[OLwin]);
  503.     XIfEvent(dpy, &event, WaitForNotify, (char*)glwins[OLwin]);
  504.     XMapWindow(dpy, glwins[GLwin]);
  505.     XIfEvent(dpy, &event, WaitForNotify, (char*)glwins[GLwin]);
  506.     XMapWindow(dpy, glwins[top]);
  507.  
  508.   /* now connect the context to the GL window */
  509.     if (!glXMakeCurrent(dpy, glwins[GLwin], glcontexts[GLwin]) == GL_TRUE) {
  510.         fprintf(stderr, "error w/glXMakeCurrent:  cudn't set");
  511.         fprintf(stderr, " context to the GL window\n");
  512.         exit(-1);
  513.     }
  514.  
  515.   /* ensure the GL colormap is installed for this app */
  516.     XSetWMColormapWindows(dpy, glwins[top], glwins, WINMAX);
  517.  
  518.   /* express interest in WM being able to kill this app */
  519.     if ((del_atom = XInternAtom(dpy, "WM_DELETE_WINDOW", True)) != None)
  520.         XSetWMProtocols(dpy, glwins[top], &del_atom, 1);
  521.  
  522.     glFlush();
  523. }
  524.  
  525.  
  526. void 
  527. initGL(void) 
  528. {
  529.     XColor colorstruct;
  530.     XColor  spix, pixel;
  531.     int OLcolorfound;
  532.  
  533.  
  534.     bell = GL_FALSE;
  535.  
  536.        /* define color map values for the GL window */
  537.     colorstruct.pixel = yellow;
  538.     colorstruct.red   = 65535;
  539.     colorstruct.green = 65535;
  540.     colorstruct.blue  = 0;
  541.     colorstruct.flags = DoRed | DoGreen | DoBlue;
  542.     XStoreColor(dpy, GLcmap, &colorstruct);
  543.     colorstruct.pixel = blue;
  544.     colorstruct.red   = 0;
  545.     colorstruct.green = 0;
  546.     colorstruct.blue  = 65535;
  547.     colorstruct.flags = DoRed | DoGreen | DoBlue;
  548.     XStoreColor(dpy, GLcmap, &colorstruct);
  549.     colorstruct.pixel = magenta;
  550.     colorstruct.red   = 65535;
  551.     colorstruct.green = 0;
  552.     colorstruct.blue  = 65535;
  553.     colorstruct.flags = DoRed | DoGreen | DoBlue;
  554.     XStoreColor(dpy, GLcmap, &colorstruct);
  555.     colorstruct.pixel = white;
  556.     colorstruct.red   = 65535;
  557.     colorstruct.green = 65535;
  558.     colorstruct.blue  = 65535;
  559.     colorstruct.flags = DoRed | DoGreen | DoBlue;
  560.     XStoreColor(dpy, GLcmap, &colorstruct);
  561.     colorstruct.pixel = beige;
  562.     colorstruct.red   = 50885;    /* was [198,113,133] rgb triplet */
  563.     colorstruct.green = 29040;
  564.     colorstruct.blue  = 29040;
  565.     colorstruct.flags = DoRed | DoGreen | DoBlue;
  566.     XStoreColor(dpy, GLcmap, &colorstruct);
  567.  
  568.   /* now try to get the overlay win's `red', `green', and `cyan' pixel values--
  569.    * we'll need these to set the read-only colormap indices for overlay drawing
  570.    */
  571.     if (OLcolorfound = XAllocNamedColor(dpy, OLcmap, "red", &spix, &pixel))
  572.         OLred = pixel.pixel;
  573.     else 
  574.         fprintf(stderr, "Bummer--no `red' color found for overlay drawing\n");
  575.     if (OLcolorfound = XAllocNamedColor(dpy, OLcmap, "green", &spix, &pixel))
  576.         OLgreen = pixel.pixel;
  577.     else
  578.         fprintf(stderr, "Bummer--no `green' color found for overlay drawing\n");
  579.     if (OLcolorfound = XAllocNamedColor(dpy, OLcmap, "cyan", &spix, &pixel))
  580.         OLcyan = pixel.pixel;
  581.     else
  582.         fprintf(stderr, "Bummer--no `cyan' color found for overlay drawing\n");
  583.  
  584.     quadObj = gluNewQuadric();
  585.     gluQuadricDrawStyle(quadObj,GLU_FILL);
  586.  
  587.     XMoveResizeWindow(dpy, glwins[GLwin], 0, 0, xsize, ysize);
  588.     XFlush(dpy);
  589.     glViewport(0, 0, xsize-1, ysize-1);
  590.     glLoadIdentity();
  591.     gluOrtho2D(0.0, 1.0, 0.0, 1.0);
  592.  
  593.   /* clear the GL window buffer's "background" */
  594.     glClearIndex(blue);
  595.     glClear(GL_COLOR_BUFFER_BIT);
  596.  
  597.     Winset(OLwin);                /* get into the overlay[/popup] bitplanes */
  598.     XMoveResizeWindow(dpy, glwins[OLwin], 0, 0, xsize, ysize);   /* to draw */
  599.     XFlush(dpy);                                                 /* their   */
  600.     glViewport(0, 0, xsize-1, ysize-1);                          /* contents*/
  601.     glLoadIdentity();
  602.     gluOrtho2D(0.0, 1.0, 0.0, 1.0);
  603.     drawovers();
  604.  
  605.     Winset(GLwin);                 /* now set context back to the GL window */
  606.     glFlush();
  607. }
  608.  
  609.  
  610. char *typeToName[] = {
  611.     "parent window",
  612.     "Cmap double buffer",
  613.     "Cmap overlay buffer",
  614. };
  615.  
  616.  
  617. /* A little helper wrapper for glXMakeCurrent.
  618.  *  passes the index to jointly access the windows and contexts array and
  619.  *  checks the return value.  This makes the call to begin GL drawing a
  620.  *  little simpler.  Building in such automatic error checking is always a
  621.  *  "smooth move" (*not* like the cancerously-mutant human with the enlarged
  622.  *  proboscis plastered all over the place urging people to be likewise 
  623.  *  smoothly cancerous and hardly cool).
  624.  */
  625. void Winset(int type)
  626. {
  627.     int rv;
  628.  
  629.     XSync(dpy,GL_FALSE);
  630.     rv = glXMakeCurrent(dpy, glwins[type], glcontexts[type]);
  631.     if (rv == GL_FALSE) {
  632.         fprintf(stderr, "glXMakeCurrent failed for a %s-type window\n",
  633.                                             typeToName[type]);
  634.         exit(-1);
  635.     }
  636. }
  637.  
  638.  
  639. static void drawovers(void) {
  640.  
  641.     glClearIndex(0);
  642.     glClear(GL_COLOR_BUFFER_BIT);
  643.     glIndexi(OLred);
  644.     glRectf(.215,  .215,  .285,  .285);       /* & draw some rectangles for */
  645.     glIndexi(OLgreen);                        /* the ball to roll underneath*/
  646.     glRectf(.515,  .515,  .585,  .585);
  647.     glIndexi(OLcyan);
  648.     glRectf(.815,  .815,  .885,  .885);
  649.     glIndexi(OLgreen);
  650.     glRectf(.877,  .527,  .947,  .597);
  651.     glRectf(.733,  .527,  .805,  .597);
  652.     glRectf(.949,  .455, 1.019,  .525);
  653.     glRectf(.805,  .455,  .875,  .525);
  654.     glRectf(.661,  .455,  .731,  .525);
  655.     glRectf(.877,  .383,  .947,  .453);
  656.     glRectf(.733,  .383,  .805,  .453);
  657.     glRectf(.589,  .383,  .659,  .453);
  658.     glRectf(.949,  .311, 1.019,  .381);
  659.     glRectf(.877,  .239,  .947,  .309);
  660.     glRectf(.805,  .311,  .875,  .381);
  661.     glRectf(.733,  .239,  .803,  .309);
  662.     glRectf(.661,  .311,  .731,  .381);
  663.     glRectf(.589,  .239,  .659,  .309);
  664.     glRectf(.519,  .311,  .587,  .381);
  665.     glRectf(.447,  .239,  .517,  .309);
  666.     glRectf(.661,  .167,  .731,  .237);
  667.     glRectf(.519,  .167,  .587,  .237);
  668.     glRectf(.375,  .167,  .445,  .237);
  669.     glRectf(.447,  .095,  .517,  .165);
  670.     glRectf(.589,  .095,  .659,  .165);
  671.     glRectf(.661,  .023,  .731,  .093);
  672.     glRectf(.519,  .023,  .587,  .093);
  673.     glRectf(.375,  .023,  .445,  .093);
  674. }
  675.  
  676.  
  677. /* rampup:
  678.  *   makes an interpolated color ramp based on the DDA algorithm from the 
  679.  *   1st arguement's index to the 2nd.  3rd and 4th are red's low and hi 
  680.  *   indices (5&6 green's, 7&8 blue's).
  681.  */
  682.  
  683. static int rampup(short first_lutv, short last_lutv,   /*start/end ramp vals*/
  684.        short minR, short maxR, short minG, short maxG,    /* lo/hi rgb vals */
  685.        short minB, short maxB) 
  686. {
  687.     unsigned short len_red, len_green, len_blue,    /* length of each color */
  688.                    i;                        /* counter for number of steps */
  689.  
  690.     float red, gre, blu;                                      /* lut values */
  691.     float rdx, gdx, bdx,                         /* sizes of rgb increments */
  692.           r, g, b,                                /* a position on the ramp */
  693.           steps;                       /* # of steps along the ramp @ which */
  694.                                       /* intensity assignments will be made */
  695.     XColor colorstruct;
  696.  
  697.     steps = (float) (last_lutv-first_lutv + 1);   /*determine length of ramp*/
  698.  
  699.     len_red   = (maxR - minR);                   /* determine length of red */
  700.     len_green = (maxG - minG);                 /* determine length of green */
  701.     len_blue  = (maxB - minB);                  /* determine length of blue */
  702.  
  703.     rdx = (float) len_red   / steps;                        /* compuke step */
  704.     gdx = (float) len_green / steps;                        /* sizes of r g */
  705.     bdx = (float) len_blue  / steps;                        /* and b values */
  706.     r = minR;                                            /* assign starting */
  707.     g = minG;                                           /* indices for each */
  708.     b = minB;                                           /* color value      */
  709.  
  710.     for (i = first_lutv; i <= last_lutv; i++) {
  711.         red = r/255.0;                                         /* round off */
  712.         gre = g/255.0;                                         /* given r g */
  713.         blu = b/255.0;                                         /* b value   */
  714.         mycolortbl[i] = i;
  715.         colorstruct.pixel = i;
  716.         colorstruct.red   = (unsigned short) (red*65535);      /* remember, */
  717.         colorstruct.green = (unsigned short) (gre*65535);      /* we've got */
  718.         colorstruct.blue  = (unsigned short) (blu*65535);      /* two bytes-*/
  719.         colorstruct.flags = DoRed | DoGreen | DoBlue;          /* worth     */
  720.         XStoreColor(dpy, GLcmap, &colorstruct);
  721.         r += rdx;                                              /* increment */
  722.         g += gdx;                                              /* color in- */
  723.         b += bdx;                                              /* dices     */
  724.     }    
  725. }
  726.